
#include <BStyle>
#include <BPainter>
#include <BMouseEvent>
#include <BScrollBar>
#include <BKeyEvent>
#include <BCursor>
#include <BSystem>

#include <BTableWidget>
#include "member_BTableWidget.h"
#include "member_BTableItem.h"
#include "member_BStyle.h"

using namespace BWE;

#define member					(*(member_BTableWidget*)_ptr)
#define member_allocate()		_ptr = new member_BTableWidget(this)
#define member_release()		delete (member_BTableWidget*)_ptr

BTableWidget::BTableWidget(BWidget* parent) : BScrollArea(parent)
{
	member_allocate();
	this->setAreaPolicy(Policy_Growing, Policy_Preferred);
}
BTableWidget::BTableWidget(const BString& title, BWidget* parent) : BScrollArea(title, parent)
{
	member_allocate();
	this->setAreaPolicy(Policy_Growing, Policy_Preferred);
}
BTableWidget::BTableWidget(int column, BWidget* parent) : BScrollArea(parent)
{
	member_allocate();
	member.items.setColumn(column);
	member.columnHeader.headers.resize(column);
	this->setAreaPolicy(Policy_Growing, Policy_Preferred);
}
BTableWidget::BTableWidget(int row, int column, BWidget* parent) : BScrollArea(parent)
{
	member_allocate();
	member.items.resize(row, column);
	member.rowHeader.headers.resize(row);
	member.columnHeader.headers.resize(column);
	this->setAreaPolicy(Policy_Growing, Policy_Preferred);
}
BTableWidget::~BTableWidget()
{
	member_release();
}

bool BTableWidget::setRowCount(int rowCount)
{
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (item->row() >= rowCount)
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			this->emit(Signal_ItemSelected, item);
		}
	}
	if (BTableItem* item = member.hoveredItem)
	{
		if (member.hoveredItem->row() >= rowCount)
		{
			member.hoveredItem = 0;
			this->emit(Signal_ItemHovered, item);
		}
	}
	if (!member.items.setRow(rowCount))
		return false;
	member.rowHeader.headers.resize(member.items.row());
	member.rowHeader.resetStatus();
	member.dirtyItems = true;
	this->fresh();
	return true;
}
int BTableWidget::rowCount() const
{
	return member.rowHeader.headers.size();
}

void BTableWidget::setRowVisible(int row, bool visible)
{
	if (member.rowHeader.headers.check(row))
	{
		IHeader& header = member.rowHeader.headers[row];
		if (header.visible != visible)
		{
			header.visible = visible;
			header.dirty = true;
			member.rowHeader.dirty = true;
			member.dirtyItems = true;
			this->fresh();
		}
	}
}
bool BTableWidget::rowVisible(int row) const
{
	return member.rowHeader.headers(row).visible;
}

bool BTableWidget::setRowLabel(int row, const BString& text)
{
	if (member.rowHeader.headers.check(row))
	{
		IHeader& header = member.rowHeader.headers[row];
		if (header.label != text)
		{
			header.label = text;
			header.dirty = true;
			member.rowHeader.dirty = true;
			member.dirtyItems = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
const BString& BTableWidget::rowLabel(int row) const
{
	return member.rowHeader.headers(row).label;
}

bool BTableWidget::setRowAlign(Align align)
{
	if (member.rowHeader.headers.empty())
		return false;
	for (int c = 0; c < member.rowHeader.headers.size(); c++)
	{
		IHeader& header = member.rowHeader.headers[c];
		if (header.ia_align != align)
		{
			header.ia_align = align;
			header.dirty = true;
		}
	}
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return true;
}
bool BTableWidget::setRowAlign(int row, Align align)
{
	if (member.rowHeader.headers.check(row))
	{
		IHeader& header = member.rowHeader.headers[row];
		if (header.ia_align != align)
		{
			header.ia_align = align;
			header.dirty = true;
			member.rowHeader.dirty = true;
			member.dirtyItems = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
Align BTableWidget::rowAlign(int row) const
{
	return member.rowHeader.headers(row).ia_align;
}

bool BTableWidget::setRowPolicy(Policy policy)
{
	if (member.rowHeader.headers.empty())
		return false;
	for (int c = 0; c < member.rowHeader.headers.size(); c++)
	{
		IHeader& header = member.rowHeader.headers[c];
		if (header.policy != policy)
		{
			header.policy = policy;
			header.dirty = true;
		}
	}
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return true;
}
bool BTableWidget::setRowPolicy(int row, Policy policy)
{
	if (member.rowHeader.headers.check(row))
	{
		IHeader& header = member.rowHeader.headers[row];
		if (header.policy != policy)
		{
			header.policy = policy;
			header.dirty = true;
			member.rowHeader.dirty = true;
			member.dirtyItems = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
Policy BTableWidget::rowPolicy(int row) const
{
	return member.rowHeader.headers(row).policy;
}

bool BTableWidget::setRowHeight(int height)
{
	if (member.rowHeader.headers.empty())
		return false;
	for (int c = 0; c < member.rowHeader.headers.size(); c++)
	{
		IHeader& header = member.rowHeader.headers[c];
		if (header.fixedSize.height() != height)
		{
			header.fixedSize.height() = height;
			header.policy = Policy_Fixed;
			header.dirty = true;
		}
	}
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return true;
}
bool BTableWidget::setRowHeight(int row, int height)
{
	if (member.rowHeader.headers.check(row))
	{
		IHeader& header = member.rowHeader.headers[row];
		if (header.fixedSize.height() != height)
		{
			header.fixedSize.height() = height;
			header.policy = Policy_Fixed;
			header.dirty = true;
			member.rowHeader.dirty = true;
			member.dirtyItems = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
int BTableWidget::rowHeight(int row) const
{
	return member.rowHeader.headers[row].rect.height();
}

bool BTableWidget::setRowWidth(int rowWidth)
{
	if (member.rowHeader.baseSize.width() != rowWidth)
	{
		member.rowHeader.baseSize.width() = rowWidth;
		member.rowHeader.dirty = true;
		this->fresh();
		return true;
	}
	return false;
}
int BTableWidget::rowWidth() const
{
	return member.rowHeader.baseSize.width();
}

void BTableWidget::setRowSpacing(int spacing)
{
	if (member.rowHeader.spacing != spacing)
	{
		member.rowHeader.spacing = spacing;
		member.rowHeader.dirty = true;
		member.dirtyItems = true;
		this->fresh();
	}
}
int BTableWidget::rowSpacing() const
{
	return member.rowHeader.spacing;
}

bool BTableWidget::setRowAsset(int row, const BValue& asset)
{
	if (member.rowHeader.headers.check(row))
	{
		IHeader& header = member.rowHeader.headers[row];
		header.asset = asset;
		return true;
	}
	return false;
}
const BValue& BTableWidget::rowAsset(int row) const
{
	return member.rowHeader.headers(row).asset;
}

bool BTableWidget::setRowColor(int row, BByte r, BByte g, BByte b, BByte a)
{
	return setRowColor(row, BColor(r, g, b, a));
}
bool BTableWidget::setRowColor(int row, const BColor& color)
{
	if (member.rowHeader.headers.check(row))
	{
		IHeader& header = member.rowHeader.headers[row];
		header.color = color;
		return true;
	}
	return false;
}
const BColor& BTableWidget::rowColor(int row) const
{
	return member.rowHeader.headers(row).color;
}
bool BTableWidget::cleanRowColor()
{
	if (member.rowHeader.headers.size())
	{
		for (int i = 0; i < member.rowHeader.headers.size(); i++)
		{
			member.rowHeader.headers[i].color.reset();
		}
		this->fresh();
		return true;
	}
	return false;
}

bool BTableWidget::setColumnCount(int columnCount)
{
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (item->column() >= columnCount)
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			this->emit(Signal_ItemSelected, item);
		}
	}
	if (BTableItem* item = member.hoveredItem)
	{
		if (member.hoveredItem->column() >= columnCount)
		{
			member.hoveredItem = 0;
			this->emit(Signal_ItemHovered, item);
		}
	}
	int count = member.items.column();
	if (count > columnCount)
	{
		return this->removeColumns(columnCount, count - columnCount);
	}
	if (!member.items.setColumn(columnCount))
		return false;
	member.columnHeader.headers.resize(columnCount);
	member.columnHeader.resetStatus();
	member.rowHeader.resetStatus();
	member.dirtyItems = true;
	this->fresh();
	return true;
}
int BTableWidget::columnCount() const
{
	return member.columnHeader.headers.size();
}

void BTableWidget::setColumnVisible(int column, bool visible)
{
	if (member.columnHeader.headers.check(column))
	{
		IHeader& header = member.columnHeader.headers[column];
		if (header.visible != visible)
		{
			header.visible = visible;
			header.dirty = true;
			member.columnHeader.dirty = true;
			member.dirtyItems = true;
			this->fresh();
		}
	}
}
bool BTableWidget::columnVisible(int column) const
{
	return member.columnHeader.headers(column).visible;
}

bool BTableWidget::setColumnLabel(int column, const BString& text)
{
	if (member.columnHeader.headers.check(column))
	{
		IHeader& header = member.columnHeader.headers[column];
		if (header.label != text)
		{
			header.label = text;
			header.dirty = true;
			member.columnHeader.dirty = true;
			member.dirtyItems = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
const BString& BTableWidget::columnLabel(int column) const
{
	return member.columnHeader.headers(column).label;
}

bool BTableWidget::setColumnAsset(int column, const BValue& asset)
{
	if (member.columnHeader.headers.check(column))
	{
		IHeader& header = member.columnHeader.headers[column];
		header.asset = asset;
		return true;
	}
	return false;
}
const BValue& BTableWidget::columnAsset(int column) const
{
	return member.columnHeader.headers(column).asset;
}

bool BTableWidget::setColumnColor(int column, BByte r, BByte g, BByte b, BByte a)
{
	return setColumnColor(column, BColor(r, g, b, a));
}
bool BTableWidget::setColumnColor(int column, const BColor& color)
{
	if (member.columnHeader.headers.check(column))
	{
		IHeader& header = member.columnHeader.headers[column];
		header.color = color;
		return true;
	}
	return false;
}
const BColor& BTableWidget::columnColor(int column) const
{
	return member.columnHeader.headers(column).color;
}
bool BTableWidget::cleanColumnColor()
{
	if (member.columnHeader.headers.size())
	{
		for (int i = 0; i < member.columnHeader.headers.size(); i++)
		{
			member.columnHeader.headers[i].color.reset();
		}
		this->fresh();
		return true;
	}
	return false;
}

int BTableWidget::addRows(int count)
{
	if (member.items.addRow(count))
	{
		member.rowHeader.headers.append(IHeader(), count);
		member.items.setRow(member.rowHeader.headers.size());
		member.rowHeader.dirty = true;
		member.dirtyItems = true;
		this->fresh();
		return member.items.row() - count;
	}
	return -1;
}
bool BTableWidget::insertRows(int pos, int count)
{
	if (member.items.insertRow(pos, count))
	{
		member.rowHeader.dirty = true;
		member.rowHeader.headers.insert(pos, IHeader(), count);
		for (auto it = member.items.seek(pos + count, 0); it.valid(); it++)
		{
			if (BTableItem* item = *it)
				item_member(item)->row = it.row();
		}
		member.dirtyItems = true;
		this->fresh();
		return true;
	}
	return false;
}
bool BTableWidget::removeRows(int pos, int count)
{
	if (pos < 0 && pos >= member.items.row())
		return false;
	if (count < 1)
		return false;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (item->row() >= pos && item->row() < pos + count)
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			this->emit(Signal_ItemSelected, item);
		}
	}
	member.hoveredItem = 0;
	for (int r = pos; r < pos + count; r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			if (BTableItem* item = member.items[r][c])
				this->removeItem(item);
		}
	}
	if (member.items.removeRow(pos, count))
	{
		for (auto it = member.items.seek(pos, 0); it.valid(); it++)
		{
			if (BTableItem* item = *it)
				item_member(item)->row = it.row();
		}
		member.selectedItems.clear();
		member.rowHeader.headers.remove(pos, count);
		member.rowHeader.resetStatus();
		member.dirtyItems = true;
		this->fresh();
		return true;
	}
	return false;
}

int BTableWidget::addColumns(int count)
{
	if (member.items.addColumn(count))
	{
		member.columnHeader.dirty = true;
		member.columnHeader.headers.append(IHeader(), count);
		member.items.setColumn(member.columnHeader.headers.size());
		member.dirtyItems = true;
		this->fresh();
		return member.items.column() - count;
	}
	return -1;
}
bool BTableWidget::insertColumns(int pos, int count)
{
	if (member.items.insertColumn(pos, count))
	{
		member.columnHeader.headers.insert(pos, IHeader(), count);
		member.columnHeader.dirty = true;
		member.dirtyItems = true;
		this->fresh();
		return true;
	}
	return false;
}
bool BTableWidget::removeColumns(int pos, int count)
{
	if (pos < 0 && pos >= member.items.column())
		return false;
	if (pos + count > member.items.column())
		count = member.items.column() - pos;
	if (count < 1)
		return false;
	int end = pos + count;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (item->column() >= pos && item->column() < end)
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			this->emit(Signal_ItemSelected, item);
		}
	}
	if (BTableItem* item = member.hoveredItem)
	{
		if (pos <= item->column() && item->column() < end)
		{
			member.hoveredItem = 0;
			this->emit(Signal_ItemHovered, 0);
			this->fresh();
		}
	}
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = pos; c < end; c++)
		{
			if (BTableItem* item = member.items[r][c])
			{
				BHolder<BTableItem> holder(item);
				member.items[r][c] = 0;
				this->emit(Signal_ItemRemoved, item);
			}
		}
	}
	member.items.removeColumn(pos, count);
	member.columnHeader.headers.remove(pos, count);
	member.columnHeader.resetStatus();
	if (member.items.empty())
	{
		member.rowHeader.headers.clear();
		member.rowHeader.resetStatus();
	}
	member.dirtyItems = true;
	this->fresh();
	return true;
}

int BTableWidget::addRow(const BString& label, float stretch)
{
	if (member.items.addRow(1))
	{
		IHeader& header = member.rowHeader.headers.append();
		header.label = label;
		if (stretch >= 0.0f)
			header.stretch = stretch;
		member.items.setRow(member.rowHeader.headers.size());
		member.rowHeader.dirty = true;
		member.dirtyItems = true;
		this->fresh();
		return member.items.row() - 1;
	}
	return -1;
}
bool BTableWidget::insertRow(int row, const BString& label, float stretch)
{
	if (member.items.insertRow(row, 1))
	{
		IHeader& header = member.rowHeader.headers.insert(row);
		header.label = label;
		if (stretch >= 0.0f)
			header.stretch = stretch;
		for (auto it = member.items.seek(row, 0); it.valid(); it++)
		{
			if (BTableItem* item = *it)
				item_member(item)->row = it.row();
		}
		member.rowHeader.dirty = true;
		member.dirtyItems = true;
		this->fresh();
		return true;
	}
	return false;
}
bool BTableWidget::removeRow(const BString& label)
{
	for (int r = 0; r < member.rowHeader.headers.size(); r++)
	{
		IHeader& header = member.rowHeader.headers[r];
		if (header.label == label)
		{
			return removeRows(r, 1);
		}
	}
	return false;
}
bool BTableWidget::removeRow(int row)
{
	if (!member.rowHeader.headers.check(row))
		return false;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (item->row() == row)
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			this->emit(Signal_ItemSelected, item);
		}
	}
	if (BTableItem* item = member.hoveredItem)
	{
		if (member.hoveredItem->row() >= row)
		{
			member.hoveredItem = 0;
			this->emit(Signal_ItemHovered, item);
		}
	}
	for (int c = 0; c < member.items.column(); c++)
	{
		if (BTableItem* item = member.items[row][c])
			this->removeItem(item);
	}
	if (member.items.removeRow(row))
	{
		for (auto it = member.items.seek(row, 0); it.valid(); it++)
		{
			if (BTableItem* item = *it)
				item_member(item)->row = it.row();
		}
		member.rowHeader.headers.remove(row, 1);
		member.rowHeader.resetStatus();
		member.dirtyItems = true;
		this->fresh();
		return true;
	}
	return false;
}

int BTableWidget::addColumn(const BString& label, float stretch)
{
	if (member.items.addColumn(1))
	{
		IHeader& header = member.columnHeader.headers.append();
		header.label = label;
		if (stretch >= 0.0f)
			header.stretch = stretch;
		member.items.setColumn(member.columnHeader.headers.size());
		member.columnHeader.dirty = true;
		member.dirtyItems = true;
		this->fresh();
		return member.items.column() - 1;
	}
	return -1;
}
bool BTableWidget::insertColumn(int column, const BString& label, float stretch)
{
	if (member.items.insertColumn(column, 1))
	{
		IHeader& header = member.columnHeader.headers.insert(column);
		header.label = label;
		if (stretch >= 0.0f)
			header.stretch = stretch;
		member.columnHeader.dirty = true;
		member.dirtyItems = true;
		this->fresh();
		return true;
	}
	return false;
}
bool BTableWidget::removeColumn(const BString& label)
{
	for (int c = 0; c < member.columnHeader.headers.size(); c++)
	{
		IHeader& header = member.rowHeader.headers[c];
		if (header.label == label)
		{
			return removeColumn(c);
		}
	}
	return false;
}
bool BTableWidget::removeColumn(int column)
{
	if (!member.columnHeader.headers.check(column))
		return false;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (item->column() == column)
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			this->emit(Signal_ItemSelected, item);
		}
	}
	if (BTableItem* item = member.hoveredItem)
	{
		if (member.hoveredItem->column() >= column)
		{
			member.hoveredItem = 0;
			this->emit(Signal_ItemHovered, item);
		}
	}
	for (int r = 0; r < member.items.row(); r++)
	{
		if (BTableItem* item = member.items[r][column])
			this->removeItem(item);
	}
	if (member.items.removeColumn(column))
	{
		for (int r = 0; r < member.items.row(); r++)
		{
			for (int c = column; c < member.items.column(); c++)
			{
				if (BTableItem* item = member.items[r][c])
					item_member(item)->row = r;
			}
		}
		member.columnHeader.headers.remove(column, 1);
		member.columnHeader.resetStatus();
		member.dirtyItems = true;
		this->fresh();
		return true;
	}
	return false;
}

bool BTableWidget::setItem(int row, int column, BTableItem* item)
{
	if (!member.items.check(row, column))
		return false;
	if (member.items[row][column] == item)
		return true;
	if (BTableItem* oldItem = member.items[row][column])
		this->removeItem(oldItem);
	if (item)
	{
		item_member(item)->table = this;
		item_member(item)->row = row;
		item_member(item)->column = column;
		if (item_member(item)->widget)
		{
			this->addChild(item_member(item)->widget);
		}
	}
	member.items[row][column] = item;
	item_member(item)->dirty = true;
	if (member.rowHeader.headers[row].policy != Policy_Fixed)
	{
		member.rowHeader.headers[row].dirty = true;
	}
	if (member.columnHeader.headers[column].policy != Policy_Fixed)
	{
		member.columnHeader.headers[column].dirty = true;
	}
	member.columnHeader.dirty = true;
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->emit(Signal_ItemInserted, item);
	this->fresh();
	return true;
}
BTableItem* BTableWidget::setItem(int row, int column, const BString& text, Form form)
{
	if (!member.items.check(row, column))
		return 0;
	BTableItemHolder item = this->item(row, column);
	if (!item)
	{
		item = new BTableItem(text, form);
		setItem(row, column, item);
	}
	else
	{
		item->setText(text);
		if (form)
			item->setForm(form);
	}
	member.columnHeader.dirty = true;
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return item;
}
BTableItem* BTableWidget::setItem(int row, int column, Graph graph, const BString& text, Form form)
{
	if (!member.items.check(row, column))
		return 0;
	BTableItemHolder item = this->item(row, column);
	if (!item)
	{
		item = new BTableItem();
		setItem(row, column, item);
	}
	item->setGraph(graph);
	item->setText(text);
	item->setForm(form);
	member.columnHeader.dirty = true;
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return item;
}
BTableItem* BTableWidget::setItem(int row, int column, BIcon* icon, const BString& text, Form form)
{
	if (!member.items.check(row, column))
		return 0;
	BTableItemHolder item = this->item(row, column);
	if (!item)
	{
		item = new BTableItem();
		setItem(row, column, item);
	}
	item->setIcon(icon);
	item->setText(text);
	item->setForm(form);
	member.columnHeader.dirty = true;
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return item;
}
BTableItem* BTableWidget::setItem(int row, int column, BImage* image, const BString& text, Form form)
{
	if (!member.items.check(row, column))
		return 0;
	BTableItemHolder item = this->item(row, column);
	if (!item)
	{
		item = new BTableItem();
		setItem(row, column, item);
	}
	item->setImage(image);
	item->setText(text);
	item->setForm(form);
	member.columnHeader.dirty = true;
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return item;
}
BTableItem* BTableWidget::setItem(int row, int column, BWidget* widget, const BString& text, Form form)
{
	if (!member.items.check(row, column))
		return 0;
	BTableItemHolder item = this->item(row, column);
	if (!item)
	{
		item = new BTableItem();
		setItem(row, column, item);
	}
	item->setWidget(widget);
	item->setText(text);
	item->setForm(form);
	member.columnHeader.dirty = true;
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return item;
}

bool BTableWidget::addItem(int row, int column, BTableItem* item)
{
	if (!item)
		return false;

	if (member.items.column() <= column)
		if (!this->setColumnCount(column + 1))
			return false;

	if (member.items.row() <= row)
		if (!this->setRowCount(row + 1))
			return false;

	if (member.items[row][column] == item)
		return true;

	if (BTableItem* oldItem = member.items[row][column])
		this->removeItem(oldItem);

	item_member(item)->table = this;
	item_member(item)->row = row;
	item_member(item)->column = column;
	if (item_member(item)->widget)
	{
		this->addChild(item_member(item)->widget);
	}

	member.items[row][column] = item;
	item_member(item)->dirty = true;
	if (member.rowHeader.headers[row].policy != Policy_Fixed)
	{
		member.rowHeader.headers[row].dirty = true;
		member.rowHeader.headers[row].dirtyItems = true;
	}
	if (member.columnHeader.headers[column].policy != Policy_Fixed)
	{
		member.columnHeader.headers[column].dirty = true;
		member.columnHeader.headers[column].dirtyItems = true;
	}
	member.columnHeader.dirty = true;
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->emit(Signal_ItemInserted, item);
	this->fresh();
	return true;
}
BTableItem* BTableWidget::addItem(int row, int column, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(text, form);
	addItem(row, column, item);
	return item;
}
BTableItem* BTableWidget::addItem(int row, int column, Graph graph, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(graph, text, form);
	addItem(row, column, item);
	return item;
}
BTableItem* BTableWidget::addItem(int row, int column, BIcon* icon, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(icon, text, form);
	addItem(row, column, item);
	return item;
}
BTableItem* BTableWidget::addItem(int row, int column, BImage* image, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(image, text, form);
	addItem(row, column, item);
	return item;
}
BTableItem* BTableWidget::addItem(int row, int column, BWidget* widget, const BString& text, Form form)
{
	if (widget)
		widget->setFloating(false);
	BTableItem* item = new BTableItem(widget, text, form);
	addItem(row, column, item);
	return item;
}

bool BTableWidget::insertItem(BTableItem* item)
{
	if (!item)
		return false;

	if (member.items.column() < 1)
		this->addColumns(1);

	if (!member.items.contain((BTableItem*)0))
		this->addRows(1);

	auto it = member.items.find((BTableItem*)0);
	if (it.valid())
	{
		return setItem(it.row(), it.column(), item);
	}
	return false;
}
BTableItem* BTableWidget::insertItem(const BString& text, Form form)
{
	BTableItem* item = new BTableItem(text, form);
	insertItem(item);
	return item;
}
BTableItem* BTableWidget::insertItem(Graph graph, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(graph, text, form);
	insertItem(item);
	return item;
}
BTableItem* BTableWidget::insertItem(BIcon* icon, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(icon, text, form);
	insertItem(item);
	return item;
}
BTableItem* BTableWidget::insertItem(BImage* image, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(image, text, form);
	insertItem(item);
	return item;
}
BTableItem* BTableWidget::insertItem(BWidget* widget, const BString& text, Form form)
{
	BTableItem* item = new BTableItem(widget, text, form);
	insertItem(item);
	return item;
}

bool BTableWidget::removeItem(int index)
{
	BTableItem* item = member.items.at(index);
	return removeItem(item);
}
bool BTableWidget::removeItem(int row, int column)
{
	BTableItem* item = member.items.at(row, column);
	return removeItem(item);
}
bool BTableWidget::removeItem(BTableItem* item)
{
	if (!item)
		return false;

	if (item_member(item)->table != this)
		return false;

	if (member.selectedItems.remove(item))
	{
		item_member(item)->selected = false;
		this->emit(Signal_ItemSelected, item);
	}

	if (member.hoveredItem == item)
		member.hoveredItem = 0;
	if (item_member(item)->widget)
		this->removeChild(item_member(item)->widget);

	BHolder<BTableItem> holder(item);
	int column = item_member(item)->column;
	int row = item_member(item)->row;
	if (member.items.check(row, column))
	{
		item_member(item)->row = -1;
		item_member(item)->column = -1;
		item_member(item)->table = 0;
		member.items[row][column] = 0;
	}
	member.columnHeader.dirty = true;
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->emit(Signal_ItemRemoved, item);
	this->fresh();
	return true;
}
void BTableWidget::clearItems()
{
	if (member.hoveredItem)
	{
		member.hoveredItem = 0;
		this->emit(Signal_ItemHovered, 0);
	}
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		item_member(item)->selected = false;
		member.selectedItems.remove(i--);
		this->emit(Signal_ItemSelected, item);
	}
	for (int i = 0; i < member.items.size(); i++)
	{
		if (BTableItem* item = member.items.at(i))
		{
			item_member(item)->row = -1;
			item_member(item)->column = -1;
			item_member(item)->table = 0;
			BHolder<BTableItem> holder(item);
			member.items.set(i, (BTableItem*)0);
			if (BWidget* widget = item_member(item)->widget)
			{
				this->removeChild(widget);
			}
			this->emit(Signal_ItemRemoved, item);
		}
	}
	member.items.clear();
	member.items.setColumn(member.columnHeader.headers.size());
	member.columnHeader.resetStatus();
	member.rowHeader.headers.clear();
	member.rowHeader.resetStatus();
	member.dirtyItems = true;
	this->fresh();
}
void BTableWidget::clear()
{
	if (member.hoveredItem)
	{
		member.hoveredItem = 0;
		this->emit(Signal_ItemHovered, 0);
	}
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		item_member(item)->selected = false;
		member.selectedItems.remove(i--);
		this->emit(Signal_ItemSelected, item);
	}
	for (int i = 0; i < member.items.size(); i++)
	{
		if (BTableItem* item = member.items.at(i))
		{
			item_member(item)->row = -1;
			item_member(item)->column = -1;
			item_member(item)->table = 0;
			BHolder<BTableItem> holder(item);
			member.items.set(i, (BTableItem*)0);
			if (BWidget* widget = item_member(item)->widget)
			{
				this->removeChild(widget);
			}
			this->emit(Signal_ItemRemoved, item);
		}
	}
	member.items.clear();
	member.columnHeader.headers.clear();
	member.columnHeader.resetStatus();
	member.rowHeader.headers.clear();
	member.rowHeader.resetStatus();
	member.dirtyItems = true;
	this->fresh();
}

bool BTableWidget::moveRow(int row, int dest)
{
	if (member.rowHeader.headers.move(row, dest) && member.items.moveRow(row, dest))
	{
		int minRow = bMin(row, dest);
		int maxRow = bMax(row, dest);
		for (auto it = member.items.seek(minRow, 0); it.row() <= maxRow; it++)
		{
			if (BTableItem* item = *it)
			{
				item_member(item)->row = it.row();
			}
		}
		member.rowHeader.resetStatus();
		member.dirtyItems = true;
		this->fresh();
		return true;
	}
	return false;
}
bool BTableWidget::moveColumn(int column, int dest)
{
	if (member.columnHeader.headers.move(column, dest) && member.items.moveColumn(column, dest))
	{
		int minColumn = bMin(column, dest);
		int maxColumn = bMax(column, dest);
		for (int r = 0; r < member.items.row(); r++)
		{
			for (int c = minColumn; c <= maxColumn; c++)
			{
				if (BTableItem* item = member.items[r][c])
				{
					item_member(item)->column = c;
				}
			}
		}
		member.columnHeader.resetStatus();
		member.dirtyItems = true;
		this->fresh();
		return true;
	}
	return false;
}

BTableItem* BTableWidget::item(int row, int column)
{
	return member.items(row, column);
}
const BTableItem* BTableWidget::item(int row, int column) const
{
	return member.items(row, column);
}

BTableItem* BTableWidget::itemOfText(const BString& text)
{
	for (auto it = member.items.begin(); it.valid(); it++)
	{
		BTableItem* item = *it;
		if (item && item_member(item)->text == text)
		{
			return *it;
		}
	}
	return 0;
}
const BTableItem* BTableWidget::itemOfText(const BString& text) const
{
	for (auto it = member.items.begin(); it.valid(); it++)
	{
		const BTableItem* item = *it;
		if (item && item_member(item)->block.text == text)
		{
			return *it;
		}
	}
	return 0;
}

BTableItem* BTableWidget::itemOfText(int column, const BString& text)
{
	if (column >= member.items.column())
		return 0;
	for (int r = 0; r < member.items.row(); r++)
	{
		BTableItem* item = member.items[r][column];
		if (item && item_member(item)->block.text == text)
		{
			return item;
		}
	}
	return 0;
}
const BTableItem* BTableWidget::itemOfText(int column, const BString& text) const
{
	if (column >= member.items.column())
		return 0;
	for (int r = 0; r < member.items.row(); r++)
	{
		const BTableItem* item = member.items[r][column];
		if (item && item_member(item)->block.text == text)
		{
			return item;
		}
	}
	return 0;
}

BTableItem* BTableWidget::itemOfWidget(const BWidget* widget)
{
	for (auto it = member.items.begin(); it.valid(); it++)
	{
		BTableItem* item = *it;
		if (item && item_member(item)->widget == widget)
		{
			return *it;
		}
	}
	return 0;
}
const BTableItem* BTableWidget::itemOfWidget(const BWidget* widget) const
{
	for (auto it = member.items.begin(); it.valid(); it++)
	{
		const BTableItem* item = *it;
		if (item && item_member(item)->widget == widget)
		{
			return *it;
		}
	}
	return 0;
}

BTableItem* BTableWidget::itemOfWidget(int column, const BWidget* widget)
{
	if (column >= member.items.column())
		return 0;
	for (int r = 0; r < member.items.row(); r++)
	{
		BTableItem* item = member.items[r][column];
		if (item && item_member(item)->widget == widget)
		{
			return item;
		}
	}
	return 0;
}
const BTableItem* BTableWidget::itemOfWidget(int column, const BWidget* widget) const
{
	if (column >= member.items.column())
		return 0;
	for (int r = 0; r < member.items.row(); r++)
	{
		const BTableItem* item = member.items[r][column];
		if (item && item_member(item)->widget == widget)
		{
			return item;
		}
	}
	return 0;
}

BTableItem* BTableWidget::itemOfAsset(const BValue& asset)
{
	if (asset.empty())
		return 0;
	for (auto it = member.items.begin(); it.valid(); it++)
	{
		if (*it && (*it)->asset() == asset)
		{
			return *it;
		}
	}
	return 0;
}
const BTableItem* BTableWidget::itemOfAsset(const BValue& asset) const
{
	if (asset.empty())
		return 0;
	for (auto it = member.items.begin(); it.valid(); it++)
	{
		if (*it && (*it)->asset() == asset)
		{
			return *it;
		}
	}
	return 0;
}

BTableItem* BTableWidget::itemOfAsset(int column, const BValue& asset)
{
	if (column >= member.items.column())
		return 0;
	for (int r = 0; r < member.items.row(); r++)
	{
		BTableItem* item = member.items[r][column];
		if (item && item->asset() == asset)
		{
			return item;
		}
	}
	return 0;
}
const BTableItem* BTableWidget::itemOfAsset(int column, const BValue& asset) const
{
	if (column >= member.items.column())
		return 0;
	for (int r = 0; r < member.items.row(); r++)
	{
		const BTableItem* item = member.items[r][column];
		if (item && item->asset() == asset)
		{
			return item;
		}
	}
	return 0;
}

BTableItem* BTableWidget::itemAt(int x, int y)
{
	return member.itemAtPoint(BPoint(x, y));
}
const BTableItem* BTableWidget::itemAt(int x, int y) const
{
	return member.itemAtPoint(BPoint(x, y));
}

BTableItem* BTableWidget::itemAt(const BPoint& pos)
{
	return member.itemAtPoint(pos);
}
const BTableItem* BTableWidget::itemAt(const BPoint& pos) const
{
	return member.itemAtPoint(pos);
}

void BTableWidget::setGridStyle(GridStyle gridStyle)
{
	if (member.gridStyle != gridStyle)
	{
		member.gridStyle = gridStyle;
		this->emit(Signal_GridChanged);
		this->fresh();
	}
}
GridStyle BTableWidget::gridStyle() const
{
	return member.gridStyle;
}

void BTableWidget::setGridSize(int gridSize)
{
	if (member.gridSize != gridSize)
	{
		member.gridSize = gridSize;
		this->emit(Signal_GridChanged);
		this->fresh();
	}
}
int BTableWidget::gridSize() const
{
	return member.gridSize;
}

void BTableWidget::setRowHeaderShown(bool rowHeaderShown)
{
	if (member.rowHeader.visible != rowHeaderShown)
	{
		member.rowHeader.visible = rowHeaderShown;
		member.rowHeader.dirty = true;
		member.dirtyItems = true;
		this->fresh();
	}
}
bool BTableWidget::rowHeaderShown() const
{
	return member.rowHeader.visible;
}

BRect BTableWidget::rowRect(int row) const
{
	if (row == -1)
	{
		BRect rect = this->rect(Part_Top);
		rect.left() = member.columnHeader.headers.first().rect.left();
		rect.right() = member.columnHeader.headers.last().rect.right();
		return rect;
	}
	if (member.rowHeader.headers.check(row))
	{
		BRect rect = member.rowHeader.headers[row].rect;
		rect.left() = member.columnHeader.headers.first().rect.left();
		rect.right() = member.columnHeader.headers.last().rect.right();
		return rect;
	}
	return BRect();
}
BRect BTableWidget::rowHeaderRect(int row) const
{
	return member.rowHeader.headers(row).rect;
}
BRect BTableWidget::rowHandleRect(int row) const
{
	return member.rowHeader.handleRect(row);
}

void BTableWidget::setColumnHeaderShown(bool columnHeaderShown)
{
	if (member.columnHeader.visible != columnHeaderShown)
	{
		member.columnHeader.visible = columnHeaderShown;
		member.columnHeader.dirty = true;
		member.dirtyItems = true;
		this->fresh();
	}
}
bool BTableWidget::columnHeaderShown() const
{
	return member.columnHeader.visible;
}

bool BTableWidget::setColumnWidth(int width)
{
	if (member.columnHeader.headers.empty())
		return false;
	for (int c = 0; c < member.columnHeader.headers.size(); c++)
	{
		IHeader& header = member.columnHeader.headers[c];
		if (header.fixedSize.width() != width)
		{
			header.fixedSize.width() = width;
			header.policy = Policy_Fixed;
			header.dirty = true;
		}
	}
	member.columnHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return true;
}
bool BTableWidget::setColumnWidth(int column, int width)
{
	if (member.columnHeader.headers.check(column))
	{
		IHeader& header = member.columnHeader.headers[column];
		if (header.fixedSize.width() != width)
		{
			header.fixedSize.width() = width;
			header.policy = Policy_Fixed;
			header.dirty = true;
			member.columnHeader.dirty = true;
			member.dirtyItems = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
int BTableWidget::columnWidth(int column) const
{
	return member.columnHeader.headers(column).rect.width();
}

bool BTableWidget::setColumnHeight(int columnHeight)
{
	if (member.columnHeader.baseSize.height() != columnHeight)
	{
		member.columnHeader.baseSize.height() = columnHeight;
		member.columnHeader.dirty = true;
		this->fresh();
		return true;
	}
	return false;
}
int BTableWidget::columnHeight() const
{
	return member.columnHeader.baseSize.height();
}

bool BTableWidget::setColumnAlign(Align align)
{
	if (member.columnHeader.headers.empty())
		return false;
	for (int c = 0; c < member.columnHeader.headers.size(); c++)
	{
		IHeader& header = member.columnHeader.headers[c];
		if (header.ia_align != align)
		{
			header.ia_align = align;
			header.dirty = true;
			member.dirtyColumnItems(c);
		}
	}
	member.columnHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return true;
}
bool BTableWidget::setColumnAlign(int column, Align align)
{
	if (member.columnHeader.headers.check(column))
	{
		IHeader& header = member.columnHeader.headers[column];
		if (header.ia_align != align)
		{
			header.ia_align = align;
			header.dirty = true;
			member.columnHeader.dirty = true;
			member.dirtyColumnItems(column);
			this->fresh();
		}
		return true;
	}
	return false;
}
Align BTableWidget::columnAlign(int column) const
{
	return member.columnHeader.headers(column).ia_align;
}

bool BTableWidget::setColumnPolicy(Policy policy)
{
	if (member.columnHeader.headers.empty())
		return false;
	for (int c = 0; c < member.columnHeader.headers.size(); c++)
	{
		IHeader& header = member.columnHeader.headers[c];
		if (header.policy != policy)
		{
			header.policy = policy;
			header.dirty = true;
			member.dirtyColumnItems(c);
		}
	}
	member.columnHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return true;
}
bool BTableWidget::setColumnPolicy(int column, Policy policy)
{
	if (member.columnHeader.headers.check(column))
	{
		IHeader& header = member.columnHeader.headers[column];
		if (header.policy != policy)
		{
			header.policy = policy;
			header.dirty = true;
			member.columnHeader.dirty = true;
			member.dirtyColumnItems(column);
			this->fresh();
		}
		return true;
	}
	return false;
}
Policy BTableWidget::columnPolicy(int column) const
{
	return member.columnHeader.headers(column).policy;
}

bool BTableWidget::setColumnStretch(float stretch)
{
	if (member.columnHeader.headers.empty())
		return false;
	for (int c = 0; c < member.columnHeader.headers.size(); c++)
	{
		IHeader& header = member.columnHeader.headers[c];
		if (header.stretch != stretch)
		{
			header.stretch = stretch;
			header.dirty = true;
			member.dirtyColumnItems(c);
		}
	}
	member.columnHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	return true;
}
bool BTableWidget::setColumnStretch(int column, float stretch)
{
	if (member.columnHeader.headers.check(column))
	{
		IHeader& header = member.columnHeader.headers[column];
		if (header.stretch != stretch)
		{
			header.stretch = stretch;
			header.dirty = true;
			member.columnHeader.dirty = true;
			member.dirtyItems = true;
			this->fresh();
		}
		return true;
	}
	return false;
}
float BTableWidget::columnStretch(int column) const
{
	return member.columnHeader.headers(column).stretch;
}

void BTableWidget::setColumnSortable(int column, bool sortable)
{
	if (member.columnHeader.headers.check(column))
	{
		IHeader& header = member.columnHeader.headers[column];
		if (header.sortable != sortable)
		{
			header.sortable = sortable;
			header.dirty = true;
			member.columnHeader.dirty = true;
			member.dirtyItems = true;
			this->fresh();
		}
	}
}
bool BTableWidget::columnSortable(int column) const
{
	return member.columnHeader.headers(column).sortable;
}

void BTableWidget::setColumnSortMode(int column, int sortMode)
{
	if (member.columnHeader.headers.check(column))
	{
		IHeader& header = member.columnHeader.headers[column];
		if (header.sortMode != sortMode)
		{
			header.sortMode = sortMode;
			header.dirty = true;
			member.columnHeader.dirty = true;
			member.dirtyItems = true;
			this->fresh();
		}
	}
}
int BTableWidget::columnSortMode(int column) const
{
	return member.columnHeader.headers(column).sortMode;
}

void BTableWidget::setColumnSpacing(int spacing)
{
	if (member.columnHeader.spacing != spacing)
	{
		member.columnHeader.spacing = spacing;
		member.columnHeader.dirty = true;
		member.dirtyItems = true;
		this->fresh();
	}
}
int BTableWidget::columnSpacing() const
{
	return member.columnHeader.spacing;
}

BRect BTableWidget::columnRect(int column) const
{
	if (member.columnHeader.headers.check(column))
	{
		BRect rect = member.columnHeader.headers(column).rect;
		rect.top() = member.rowHeader.headers.first().rect.top();
		rect.bottom() = member.rowHeader.headers.last().rect.bottom();
		return rect;
	}
	return BRect();
}
BRect BTableWidget::columnHeaderRect(int column) const
{
	return member.columnHeader.headers(column).rect;
}
BRect BTableWidget::columnHandleRect(int column) const
{
	return member.columnHeader.handleRect(column);
}

void BTableWidget::setSelectMode(SelectMode selectMode)
{
	if (member.selectMode != selectMode)
	{
		member.selectMode = selectMode;
		member.selectedItems.clear();
		this->fresh();
	}
}
SelectMode  BTableWidget::selectMode() const
{
	return member.selectMode;
}

bool BTableWidget::setSelection(BTableItem* selectedItem)
{
	bool selectionChanged = false;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (selectedItem != item)
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	if (!member.selectedItems.contain(selectedItem))
	{
		item_member(selectedItem)->selected = true;
		member.selectedItems.append(selectedItem);
		emit(Signal_ItemSelected, selectedItem);
		selectionChanged = true;
	}
	if (selectionChanged)
	{
		emit(Signal_SelectionChanged, member.selectedItems.size());
		this->fresh();
		return true;
	}
	return false;
}
bool BTableWidget::setSelection(const BIntArray& selectedRows)
{
	if (0 == (member.selectMode & Select_Rows))
		return false;
	bool selectionChanged = false;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (!selectedRows.contain(item->row()))
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	for (int i = 0; i < selectedRows.size(); i++)
	{
		BTableItem* item = member.items(selectedRows[i], 0);
		if (item && !member.selectedItems.contain(item))
		{
			item_member(item)->selected = true;
			member.selectedItems.append(item);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	if (selectionChanged)
	{
		emit(Signal_SelectionChanged, member.selectedItems.size());
		this->fresh();
		return true;
	}
	return false;
}
bool BTableWidget::setSelection(const BTableItemArray& selection)
{
	bool selectionChanged = false;
	for (int i = 0; i < member.selectedItems.size(); i++)
	{
		BTableItem* item = member.selectedItems[i];
		if (!selection.contain(item))
		{
			item_member(item)->selected = false;
			member.selectedItems.remove(i--);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	for (int i = 0; i < selection.size(); i++)
	{
		BTableItem* item = selection[i];
		if (!member.selectedItems.contain(item))
		{
			item_member(item)->selected = true;
			member.selectedItems.append(item);
			emit(Signal_ItemSelected, item);
			selectionChanged = true;
		}
	}
	if (selectionChanged)
	{
		emit(Signal_SelectionChanged, member.selectedItems.size());
		this->fresh();
		return true;
	}
	return false;
}
const BTableItemArray& BTableWidget::selection() const
{
	return member.selectedItems;
}

bool BTableWidget::setItemSelected(BTableItem* item, bool selected)
{
	if (!item)
		return false;
	if (member.selectMode & Select_Rows && item_member(item)->column > 0)
	{
		item = member.items[item_member(item)->row][0];
	}
	if (selected && !member.selectedItems.contain(item))
	{
		if (member.selectMode & Select_Single)
		{
			for (int i = 0; i < member.selectedItems.size(); i++)
			{
				BTableItem* selectedItem = member.selectedItems[i];
				item_member(selectedItem)->selected = false;
				member.selectedItems.remove(i--);
				this->emit(Signal_ItemSelected, selectedItem);
			}
		}
		item_member(item)->selected = true;
		member.selectedItems.append(item);
		emit(Signal_ItemSelected, item);
		emit(Signal_SelectionChanged, member.selectedItems.size());
		this->fresh();
		return true;
	}
	if (!selected && member.selectedItems.contain(item))
	{
		BHolder<BTableItem> holder = item;
		item_member(item)->selected = false;
		member.selectedItems.remove(item);
		emit(Signal_ItemSelected, item);
		emit(Signal_SelectionChanged, member.selectedItems.size());
		this->fresh();
		return true;
	}
	return true;
}
bool BTableWidget::setRowSelected(int row, bool selected)
{
	if (!member.items.check(row, 0))
		return false;
	if (selected)
	{
		if (member.selectMode & Select_Rows)
		{
			BTableItem* item = member.items(row, 0);
			this->setItemSelected(item, true);
		}
		else
		{
			for (int c = 0; c < member.items.column(); c++)
			{
				BTableItem* item = member.items[row][c];
				this->setItemSelected(item, true);
			}
		}
		return true;
	}
	if (!selected)
	{
		if (member.selectMode & Select_Rows)
		{
			BTableItem* item = member.items(row, 0);
			this->setItemSelected(item, false);
		}
		else
		{
			for (int c = 0; c < member.items.column(); c++)
			{
				BTableItem* item = member.items[row][c];
				this->setItemSelected(item, false);
			}
		}
		return true;
	}
	return true;
}
bool BTableWidget::setColumnSelected(int column, bool selected)
{
	if (!member.items.check(0, column))
		return false;
	if (selected)
	{
		if (member.selectMode & Select_Rows)
		{
			BTableItem* item = member.items(0, column);
			this->setItemSelected(item, true);
		}
		else
		{
			for (int r = 0; r < member.items.row(); r++)
			{
				BTableItem* item = member.items[r][column];
				this->setItemSelected(item, true);
			}
		}
		return true;
	}
	if (!selected)
	{
		if (member.selectMode & Select_Rows)
		{
			BTableItem* item = member.items(0, column);
			this->setItemSelected(item, false);
		}
		else
		{
			for (int r = 0; r < member.items.row(); r++)
			{
				BTableItem* item = member.items[r][column];
				this->setItemSelected(item, false);
			}
		}
		return true;
	}
	return true;
}
bool BTableWidget::clearSelection()
{
	if (member.selectedItems.size())
	{
		while (BTableItem* item = member.selectedItems.last())
		{
			item_member(item)->selected = false;
			member.selectedItems -= item;
			this->emit(Signal_ItemSelected, item);
		}
		this->fresh();
		return true;
	}
	return false;
}

int BTableWidget::selectedItemCount() const
{
	return member.selectedItems.size();
}
BTableItem* BTableWidget::selectedItem(int index)
{
	return member.selectedItems(index);
}
const BTableItem* BTableWidget::selectedItem(int index) const
{
	return member.selectedItems(index);
}

int BTableWidget::rowOfAsset(const BValue& asset)
{
	for (int r = 0; r < member.rowHeader.headers.size(); r++)
	{
		if (member.rowHeader.headers[r].asset == asset)
			return r;
	}
	return -1;
}
int BTableWidget::columnOfAsset(const BValue& asset)
{
	for (int c = 0; c < member.columnHeader.headers.size(); c++)
	{
		if (member.columnHeader.headers[c].asset == asset)
			return c;
	}
	return -1;
}

int BTableWidget::rowAt(const BPoint& pos) const
{
	return rowAt(pos.y());
}
int BTableWidget::rowAt(int y) const
{
	if (y > this->area().bottom())
		return member.rowHeader.headers.size();
	for (int i = 0; i < member.rowHeader.headers.size(); i++)
	{
		IHeader& sec = member.rowHeader.headers[i];
		BRect rect = sec.rect;
		if (rect.top() < y && rect.bottom() > y)
		{
			return i;
		}
	}
	return -1;
}
int BTableWidget::columnAt(const BPoint& pos) const
{
	return rowAt(pos.x());
}
int BTableWidget::columnAt(int x) const
{
	if (x > this->area().right())
		return member.columnHeader.headers.size();
	for (int i = 0; i < member.columnHeader.headers.size(); i++)
	{
		IHeader& header = member.columnHeader.headers[i];
		BRect rect = header.rect;
		if (rect.left() < x && rect.right() > x)
		{
			return i;
		}
	}
	return -1;
}

bool BTableWidget::check(int index) const
{
	return member.items.check(index);
}
bool BTableWidget::checkRow(int row) const
{
	return row >= 0 && row < member.items.row();
}
bool BTableWidget::checkColumn(int column) const
{
	return column >= 0 && column < member.items.column();
}
bool BTableWidget::checkCell(int row, int column) const
{
	return member.items.check(row, column);
}

BRect BTableWidget::cellRect(int row, int column) const
{
	if (member.items.check(row, column))
	{
		const BRect& colRect = member.columnHeader.headers[column].rect;
		const BRect& rowRect = member.rowHeader.headers[row].rect;
		return BRect(colRect.x(), rowRect.y(), colRect.width(), rowRect.height());
	}
	return BRect();
}
bool BTableWidget::scrollToItem(BTableItem* item, Align align)
{
	if (!item)
		return false;
	this->flush();
	BRect rect = item->rect();
	return this->scrollToRect(rect, align);
}
bool BTableWidget::scrollToCell(int row, int column, Align align)
{
	if (!member.items.check(row, column))
		return false;
	this->flush();
	const BRect& colRect = member.columnHeader.headers[column].rect;
	const BRect& rowRect = member.rowHeader.headers[row].rect;
	BRect rect(colRect.x(), rowRect.y(), colRect.width(), rowRect.height());
	return this->scrollToRect(rect, align);
}

bool BTableWidget::sortColumn(int column)
{
	if (column < 0)
	{
		for (int i = 0; i < member.columnHeader.headers.size(); i++)
		{
			if (member.columnHeader.headers[i].sortable)
			{
				column = i;
				break;
			}
		}
	}
	if (!member.columnHeader.headers.check(column))
		return false;
	int mode = member.columnHeader.headers[column].sortMode;
	if (mode == 0)
		return false;
	for (int row = 0; row < member.items.row(); row++)
	{
		int select = row;
		BTableItem* setItemSelected = member.items[row][column];
		if (!setItemSelected)
			continue;
		for (int r = row + 1; r < member.items.row(); r++)
		{
			BTableItem* item = member.items[r][column];
			if (!item)
				continue;
			if (mode < 0 && setItemSelected->text() > item->text())
			{
				setItemSelected = item;
				select = r;
			}
			if (mode > 0 && setItemSelected->text() < item->text())
			{
				setItemSelected = item;
				select = r;
			}
		}
		if (select != row)
		{
			member.items.moveRow(select, row);
		}
		for (int c = 0; c < member.items.column(); c++)
		{
			if (BTableItem* item = member.items[row][c])
				item_member(item)->row = row;
		}
	}
	member.dirtyItems = true;
	this->fresh();
	return true;
}

bool BTableWidget::query(const BString& text, BValue& value) const
{
	if (text == "hovered-item")
	{
		value = member.hoveredItem;
		return true;
	}
	if (text == "visual-items")
	{
		BTableItemArray& visualItems = value.fill<BTableItemArray>();
		for (int r = member.rowHeader.show_begin; r < member.rowHeader.show_end; r++)
		{
			for (int c = member.columnHeader.show_begin; c < member.columnHeader.show_end; c++)
			{
				if (BTableItem* item = member.items[r][c])
					visualItems.append(item);
			}
		}
		return true;
	}
	if (text == "selected-items")
	{
		BTableItemArray& items = value.fill<BTableItemArray>();
		items = member.selectedItems;
		return true;
	}
	return BScrollArea::query(text, value);
}

void BTableWidget::scrolling(Orientation orientation)
{
	member.columnHeader.dirty = true;
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
	this->fresh();
	BScrollArea::scrolling(orientation);
}

void BTableWidget::resizeEvent(const BEvent& event)
{
	BScrollArea::resizeEvent(event);
	member.columnHeader.dirty = true;
	member.rowHeader.dirty = true;
	member.dirtyItems = true;
}

void BTableWidget::styleEvent(const BEvent& event)
{
	BScrollArea::styleEvent(event);

	const BStyle* style = this->realStyle();

	style_member(style)->assign(Value_Spacing, member.rowHeader.spacing);
	style_member(style)->assign(Value_Spacing, member.columnHeader.spacing);

	style_member(style)->assign(Value_VerSpacing, member.rowHeader.spacing);
	style_member(style)->assign(Value_HorSpacing, member.columnHeader.spacing);

	style_member(style)->assign(Value_Grid_Style, member.gridStyle);
	style_member(style)->assign(Value_Grid_Size, member.gridSize);

	member.autoTop = style->value(Value_Perch_Top).empty();
	member.autoLeft = style->value(Value_Perch_Left).empty();

	if (member.rowHeader.style)
		member.rowHeader.style->clearAll();
	if (member.columnHeader.style)
		member.columnHeader.style->clearAll();
	if (const BStyle* headerStyle = style->annex("header"))
	{
		member.rowHeader.applyStyle(headerStyle);
		member.columnHeader.applyStyle(headerStyle);
	}
	if (const BStyle* headerStyle = style->annex("row-header"))
	{
		member.rowHeader.applyStyle(headerStyle);
	}
	if (const BStyle* headerStyle = style->annex("column-header"))
	{
		member.columnHeader.applyStyle(headerStyle);
	}

	member.dirtyItems = true;
	for (int r = 0; r < member.items.row(); r++)
	{
		for (int c = 0; c < member.items.column(); c++)
		{
			BTableItem* item = member.items[r][c];
			if (!item)
				continue;
			item_member(item)->dirty = true;
			item_member(item)->dirtyStyle = true;
		}
	}

	member.columnHeader.dirty = true;
	for (int i = 0; i < member.columnHeader.headers.size(); i++)
	{
		member.columnHeader.headers[i].dirty = true;
		member.columnHeader.headers[i].dirtyItems = true;
	}

	member.rowHeader.dirty = true;
	for (int i = 0; i < member.rowHeader.headers.size(); i++)
	{
		member.rowHeader.headers[i].dirty = true;
		member.rowHeader.headers[i].dirtyItems = true;
	}

}
void BTableWidget::freshEvent(const BEvent& event)
{
	if (member.columnHeader.dirty || member.rowHeader.dirty)
	{
		member.adjustHeader();
		member.dirtyItems = true;
		this->emit(Signal_Flushed);
	}

	if (member.dirtyItems)
	{
		member.adjustItemRects();
		member.dirtyItems = false;
		this->emit(Signal_Flushed);
	}

	BPerch perch = this->perch();
	if (member.autoTop && !this->titleVisible())
	{
		perch.top() = this->preferSize(Part_Top).height();
		if (member.columnHeader.visible && perch.top() < member.columnHeader.hintSize.height())
			perch.top() = member.columnHeader.hintSize.height();
	}
	if (member.autoLeft)
	{
		perch.left() = this->preferSize(Part_Left).width();
		if (member.rowHeader.visible && perch.left() < member.rowHeader.hintSize.width())
			perch.left() = member.rowHeader.hintSize.width();
	}
	this->setPerch(perch);

	BScrollArea::freshEvent(event);
}
void BTableWidget::paintEvent(const BEvent& event)
{
	BScrollArea::paintEvent(event);

	BPainter painter(this);

	BPoint offset = this->offset();
	BRect crect = this->centerRect();
	painter.setClip(crect);

	int row_begin = member.rowHeader.show_begin;
	int row_end = member.rowHeader.show_end;
	int col_begin = member.columnHeader.show_begin;
	int col_end = member.columnHeader.show_end;
	for (int r = row_begin; r < row_end; r++)
	{
		if (!member.rowHeader.headers[r].visible)
			continue;
		if (painter.setColor(member.rowHeader.headers[r].color))
		{
			BRect rect = member.rowHeader.headers[r].rect;
			rect.left() = member.columnHeader.headers.first().rect.left();
			rect.right() = member.columnHeader.headers.last().rect.right();
			painter.fillRect(rect);
		}
	}
	for (int c = col_begin; c < col_end; c++)
	{
		if (!member.columnHeader.headers[c].visible)
			continue;
		if (painter.setColor(member.columnHeader.headers[c].color))
		{
			BRect rect = member.columnHeader.headers[c].rect;
			rect.top() = member.rowHeader.headers.first().rect.top();
			rect.bottom() = member.rowHeader.headers.last().rect.bottom();
			painter.fillRect(rect);
		}
	}

	int halfRowSpace = member.rowHeader.spacing / 2;
	int halfColumnSpace = member.columnHeader.spacing / 2;
	if (member.gridStyle & Grid_Horizontal && member.rowHeader.headers.size() > 0 && member.gridSize > 0)
	{
		painter.setLineWidth((float)member.gridSize);
		if (painter.setColor(Color_Grid_Hor))
		{
			painter.setLineWidth((float)member.gridSize);
			int x0 = member.columnHeader.headers.first().rect.left() - halfColumnSpace;
			int x1 = member.columnHeader.headers.last().rect.right() + halfColumnSpace;
			if (member.rowHeader.headers.size())
			{
				int y = member.rowHeader.headers[0].rect.top() - halfRowSpace;
				painter.drawLine(x0, y, x1, y);
			}
			for (int r = 0; r < member.rowHeader.headers.size(); r++)
			{
				int y = member.rowHeader.headers[r].rect.bottom() + halfRowSpace;
				painter.drawLine(x0, y, x1, y);
			}
		}
	}
	if (member.gridStyle & Grid_Vertical && member.columnHeader.headers.size() > 1 && member.gridSize > 0)
	{
		painter.setLineWidth((float)member.gridSize);
		if (painter.setColor(Color_Grid_Ver))
		{
			painter.setLineWidth((float)member.gridSize);
			int y0 = member.rowHeader.headers.first().rect.top() - halfRowSpace;
			int y1 = member.rowHeader.headers.last().rect.bottom() + halfRowSpace;
			if (member.columnHeader.headers.size())
			{
				int x = member.columnHeader.headers[0].rect.left() - halfColumnSpace;
				painter.drawLine(x, y0, x, y1);
			}
			for (int c = 0; c < member.columnHeader.headers.size(); c++)
			{
				int x = member.columnHeader.headers[c].rect.right() + halfColumnSpace;
				painter.drawLine(x, y0, x, y1);
			}
		}
	}

	State state = painter.state();
	for (int r = row_begin; r < row_end; r++)
	{
		if (!member.rowHeader.headers[r].visible)
			continue;
		for (int c = col_begin; c < col_end; c++)
		{
			if (!member.columnHeader.headers[c].visible)
				continue;
			BTableItem* item = member.items[r][c];
			if (!item)
				continue;
			State itemState = state;
			if (item_member(item)->checked)
				itemState = State_Checked;
			if (!item->enabled())
				itemState = State_Disable;
			if ((member.selectMode & Select_Rows))
			{
				if (member.pressedItem && member.pressedItem->row() == item->row())
					itemState |= State_Pressed;
				else if (member.hoveredItem && member.hoveredItem->row() == item->row())
					itemState |= State_Hovered;
				else
				{
					for (int i = 0; i < member.selectedItems.size(); i++)
					{
						BTableItem* selectedItem = member.selectedItems[i];
						if (selectedItem->row() == item->row())
						{
							itemState |= State_Selected;
							break;
						}
					}
				}
			}
			else
			{
				if (member.pressedItem == item)
					itemState |= State_Pressed;
				if (member.hoveredItem == item)
					itemState |= State_Hovered;
				else if (member.selectedItems.contain(item))
					itemState |= State_Selected;
			}

			painter.setClip(item_member(item)->rect() & crect);
			painter.setStyle(item_member(item)->realStyle);

			painter.pushMatrix();
			painter.translate(item_member(item)->pos);
			item_member(item)->drawBackground(painter, itemState);
			if (item_member(item)->margin.valid())
				item_member(item)->drawMargin(painter, itemState);
			if (item_member(item)->border > 0)
				item_member(item)->drawBorder(painter, itemState);
			item_member(item)->drawContent(painter, itemState);
			painter.popMatrix();
		}
	}

	painter.setClip(this->size());

	if (!this->titleVisible())
	{
		BRect topRect = this->rect(Part_Top);
		if (member.columnHeader.visible && topRect.valid())
		{
			painter.setClip(topRect);
			member.columnHeader.paint(painter);
			painter.setClip(this->size());
		}

		BRect leftRect = this->rect(Part_Left);
		if (member.rowHeader.visible && leftRect.valid())
		{
			painter.setClip(leftRect);
			member.rowHeader.paint(painter);
			painter.setClip(this->size());
		}
	}

	if (member.selecting)
	{
		painter.setColor(Color_Wire);
		painter.drawRect(member.selectRect);
	}
}

void BTableWidget::keyPressEvent(const BKeyEvent& keyEvent)
{
	Key key = keyEvent.key();
	BScrollArea::keyPressEvent(keyEvent);
}
void BTableWidget::keyReleaseEvent(const BKeyEvent& keyEvent)
{
	Key key = keyEvent.key();
	BScrollArea::keyReleaseEvent(keyEvent);
}

void BTableWidget::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	BScrollArea::mouseEnterEvent(mouseEvent);
}
void BTableWidget::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	if (member.columnHeader.hoverIndex >= 0)
	{
		member.columnHeader.hoverIndex = -1;
		this->fresh();
	}
	if (member.rowHeader.hoverIndex >= 0)
	{
		member.rowHeader.hoverIndex = -1;
		this->fresh();
	}
	if (member.hoveredItem)
	{
		member.hoveredItem = 0;
		this->fresh();
	}
	BScrollArea::mouseLeaveEvent(mouseEvent);
}

void BTableWidget::mousePressEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	if (mouseEvent.button() == Button_Left)
	{
		const BRect& topRect = this->rect(Part_Top);
		if (topRect.contain(pos))
		{
			if (member.columnHeader.handleIndex >= 0)
			{
				member.columnHeader.dragBegin(pos);
				this->fresh();
				return;
			}
			if (member.columnHeader.hoverIndex >= 0)
			{
				member.columnHeader.pressed = true;
				this->fresh();
				return;
			}
		}
		const BRect& leftRect = this->rect(Part_Left);
		if (leftRect.contain(pos))
		{
			if (member.rowHeader.handleIndex >= 0)
			{
				member.rowHeader.dragBegin(pos);
				this->fresh();
				return;
			}
			if (member.rowHeader.hoverIndex >= 0)
			{
				member.rowHeader.pressed = true;
				this->fresh();
				return;
			}
		}
		const BRect& centerRect = this->rect(Part_Center);
		if (centerRect.contain(pos))
		{
			if (member.hoveredItem == 0)
			{
				member.selecting = true;
				member.pressedPoint = mouseEvent.pos();
				member.selectRect.reset(member.pressedPoint);
			}
			if (member.pressedItem != member.hoveredItem)
			{
				member.pressedItem = member.hoveredItem;
				this->fresh();
			}
		}
	}
	BScrollArea::mousePressEvent(mouseEvent);
}
void BTableWidget::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		if (member.selecting)
		{
			member.selecting = false;
			this->fresh();
		}
		if (member.pressedItem)
		{
			member.pressedItem = 0;
			this->fresh();
		}
	}
	if (member.columnHeader.draging)
	{
		member.columnHeader.draging = false;
		this->emit(Signal_ColumnDragFinished, member.columnHeader.handleIndex);
		this->fresh();
	}
	if (member.columnHeader.pressed)
	{
		member.columnHeader.pressed = false;
		this->fresh();
	}
	if (member.rowHeader.draging)
	{
		member.rowHeader.draging = false;
		this->emit(Signal_RowDragFinished, member.rowHeader.handleIndex);
		this->fresh();
	}
	if (member.rowHeader.pressed)
	{
		member.rowHeader.pressed = false;
		this->fresh();
	}
	BScrollArea::mouseReleaseEvent(mouseEvent);
}
void BTableWidget::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	if (member.selecting)
	{
		member.selectRect.reset(member.pressedPoint);
		member.selectRect.expand(pos);
		if (member.selectItemsInside())
		{
			this->emit(Signal_SelectionChanged, member.selectedItems.size());
		}
		this->fresh();
		return;
	}

	if (member.columnHeader.draging)
	{
		if (member.columnHeader.drag(pos))
		{
			member.columnHeader.dirty = true;
			member.dirtyColumnItems(member.columnHeader.handleIndex);
			this->emit(Signal_ColumnDragged, member.columnHeader.handleIndex);
			this->fresh();
		}
		return;
	}

	if (member.rowHeader.draging)
	{
		if (member.rowHeader.drag(pos))
		{
			member.rowHeader.dirty = true;
			member.dirtyRowItems(member.rowHeader.handleIndex);
			this->emit(Signal_RowDragged, member.rowHeader.handleIndex);
			this->fresh();
		}
		return;
	}

	BTableItem* hoveredItem = member.itemAtPoint(pos);
	if (member.hoveredItem != hoveredItem)
	{
		member.hoveredItem = hoveredItem;
		emit(Signal_ItemHovered, hoveredItem);
		this->fresh();
	}

	if (member.columnHeader.visible && !this->titleVisible())
	{
		const BRect& topRect = this->rect(Part_Top);

		int handleIndex = -1;
		if (topRect.contain(pos))
			handleIndex = member.columnHeader.handleUnderPoint(pos);
		if (member.columnHeader.handleIndex != handleIndex)
		{
			member.columnHeader.handleIndex = handleIndex;
			if (handleIndex < 0)
				this->setCursor(Cursor_None);
			else
				this->setCursor(Cursor_SizeHor);
			this->fresh();
		}
		int hoverIndex = -1;
		if (handleIndex < 0 && topRect.contain(pos))
			hoverIndex = member.columnHeader.sectionUnderPoint(pos);
		if (member.columnHeader.hoverIndex != hoverIndex)
		{
			member.columnHeader.hoverIndex = hoverIndex;
			this->fresh();
		}
	}

	if (member.rowHeader.visible)
	{
		const BRect& leftRect = this->rect(Part_Left);

		int handleIndex = -1;
		if (leftRect.contain(pos))
			handleIndex = member.rowHeader.handleUnderPoint(pos);
		if (member.rowHeader.handleIndex != handleIndex)
		{
			member.rowHeader.handleIndex = handleIndex;
			if (handleIndex < 0)
				this->setCursor(Cursor_None);
			else
				this->setCursor(Cursor_SizeVer);
			this->fresh();
		}
		int hoverIndex = -1;
		if (handleIndex < 0 && leftRect.contain(pos))
			hoverIndex = member.rowHeader.sectionUnderPoint(pos);
		if (member.rowHeader.hoverIndex != hoverIndex)
		{
			member.rowHeader.hoverIndex = hoverIndex;
			this->fresh();
		}
	}
	BScrollArea::mouseMoveEvent(mouseEvent);
}

void BTableWidget::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	BTableItem* hoveredItem = member.hoveredItem;
	if (mouseEvent.button() == Button_Left)
	{
		if (member.rowHeader.hoverIndex >= 0)
		{
			IHeader& header = member.rowHeader.headers[member.rowHeader.hoverIndex];
			if (header.sortable)
			{
				if (header.sortMode == 0)
					header.sortMode = -1;
				else
					header.sortMode = -header.sortMode;
				for (int i = 0; i < member.rowHeader.headers.size(); i++)
				{
					IHeader& sec = member.rowHeader.headers[i];
					if (member.rowHeader.hoverIndex != i)
						sec.sortMode = 0;
				}
				this->sortColumn(member.rowHeader.hoverIndex);
			}
			this->emit(Signal_RowClicked, member.rowHeader.hoverIndex);
			return;
		}
		if (member.columnHeader.hoverIndex >= 0)
		{
			IHeader& header = member.columnHeader.headers[member.columnHeader.hoverIndex];
			if (header.sortable)
			{
				if (header.sortMode == 0)
					header.sortMode = -1;
				else
					header.sortMode = -header.sortMode;
				for (int i = 0; i < member.columnHeader.headers.size(); i++)
				{
					IHeader& sec = member.columnHeader.headers[i];
					if (member.columnHeader.hoverIndex != i)
						sec.sortMode = 0;
				}
				this->sortColumn(member.columnHeader.hoverIndex);
			}
			this->emit(Signal_ColumnClicked, member.columnHeader.hoverIndex);
			return;
		}
		if (hoveredItem && member.selectMode & Select_Rows)
		{
			hoveredItem = member.items[hoveredItem->row()][0];
		}
		if (member.selectMode & Select_Multiple)
		{
			if (hoveredItem && BSystem::KeyState(Key_Shift))
			{
				if (member.selectedItems.empty())
				{
					member.selectedItems.append(hoveredItem);
					item_member(hoveredItem)->selected = true;
					emit(Signal_ItemSelected, hoveredItem);
					this->fresh();
				}
				else
				{
					BArray<BTableItem*> items;
					BTableItem* shiftItem = member.selectedItems.first();
					if (member.selectMode & Select_Rows)
					{
						int row_begin = bMin(hoveredItem->row(), shiftItem->row());
						int row_end = bMax(hoveredItem->row(), shiftItem->row());
						for (int r = row_begin; r <= row_end; r++)
						{
							if (BTableItem* item = member.items[r][0])
								items.append(item);
						}
					}
					else if (member.selectMode & Select_Columns)
					{
						int column_begin = bMin(hoveredItem->row(), shiftItem->row());
						int column_end = bMax(hoveredItem->row(), shiftItem->row());
						for (int c = column_begin; c <= column_end; c++)
						{
							if (BTableItem* item = member.items[0][c])
								items.append(item);
						}
					}
					else
					{
						int index0 = hoveredItem->row() * member.items.column() + hoveredItem->column();
						int index1 = shiftItem->row() * member.items.column() + shiftItem->column();
						int index_begin = bMin(index0, index1);
						int index_end = bMax(index0, index1);
						for (auto it = member.items.seek(index_begin); it.index() <= index_end; ++it)
						{
							if (BTableItem* item = *it)
								items.append(item);
						}
					}
					for (int i = 0; i < member.selectedItems.size(); i++)
					{
						hoveredItem = member.selectedItems[i];
						if (!items.contain(hoveredItem))
						{
							i--;
							item_member(hoveredItem)->selected = false;
							member.selectedItems.remove(hoveredItem);
							this->emit(Signal_ItemSelected, hoveredItem);
						}
					}
					for (int i = 0; i < items.size(); i++)
					{
						hoveredItem = items[i];
						if (!member.selectedItems.contain(hoveredItem))
						{
							item_member(hoveredItem)->selected = true;
							member.selectedItems.append(hoveredItem);
							this->emit(Signal_ItemSelected, hoveredItem);
						}
					}
					this->emit(Signal_SelectionChanged, member.selectedItems.size());
					this->fresh();
				}
			}
			else if (hoveredItem && BSystem::KeyState(Key_Ctrl))
			{
				if (member.selectedItems.contain(hoveredItem))
				{
					item_member(hoveredItem)->selected = false;
					member.selectedItems.remove(hoveredItem);
					this->emit(Signal_ItemSelected, hoveredItem);
				}
				else
				{
					item_member(hoveredItem)->selected = true;
					member.selectedItems.append(hoveredItem);
					this->emit(Signal_ItemSelected, hoveredItem);
				}
				this->emit(Signal_SelectionChanged, member.selectedItems.size());
				this->fresh();
			}
			else
			{
				for (int i = 0; i < member.selectedItems.size(); i++)
				{
					BTableItem* old_item = member.selectedItems[i];
					if (old_item != hoveredItem)
					{
						i--;
						item_member(old_item)->selected = false;
						member.selectedItems.remove(old_item);
						this->emit(Signal_ItemSelected, old_item);
					}
				}
				if (member.selectedItems.empty() && hoveredItem)
				{
					member.selectedPos = pos;
					member.selectedItems.append(hoveredItem);
					item_member(hoveredItem)->selected = true;
					this->emit(Signal_ItemSelected, hoveredItem);
				}
				this->emit(Signal_SelectionChanged, member.selectedItems.size());
				this->fresh();
			}
		}
		else
		{
			for (int i = 0; i < member.selectedItems.size(); i++)
			{
				BTableItem* selectedItem = member.selectedItems[i];
				if (selectedItem != hoveredItem)
				{
					item_member(selectedItem)->selected = false;
					member.selectedItems.remove(i--);
					this->emit(Signal_ItemSelected, selectedItem);
				}
			}
			if (hoveredItem && member.selectedItems.empty())
			{
				member.selectedPos = pos;
				member.selectedItems.append(hoveredItem);
				item_member(hoveredItem)->selected = true;
				this->emit(Signal_ItemSelected, hoveredItem);
			}
			this->emit(Signal_SelectionChanged, member.selectedItems.size());
			this->fresh();
		}
		this->emit(Signal_ItemClicked, member.hoveredItem);
	}
	else if (mouseEvent.button() == Button_Right)
	{
		if (member.rowHeader.hoverIndex >= 0)
			this->emit(Signal_RowRightClicked, member.rowHeader.hoverIndex);
		else if (member.columnHeader.hoverIndex >= 0)
			this->emit(Signal_ColumnRightClicked, member.columnHeader.hoverIndex);
		else
			this->emit(Signal_ItemRightClicked, BValue(hoveredItem, &mouseEvent));
	}
	BScrollArea::mouseClickEvent(mouseEvent);
}
void BTableWidget::mouseDoubleClickEvent(const BMouseEvent& mouseEvent)
{
	if (mouseEvent.button() == Button_Left)
	{
		const BPoint& pos = mouseEvent.pos();
		BTableItem* hoveredItem = member.itemAtPoint(pos);
		if (hoveredItem && member.selectMode & Select_Rows)
		{
			hoveredItem = member.items[hoveredItem->row()][0];
		}
		if (hoveredItem)
		{
			emit(Signal_ItemDoubleClicked, hoveredItem);
		}
	}
	BScrollArea::mouseDoubleClickEvent(mouseEvent);
}
